from pointLibrary import *
from ColorLib import *
from LoadLib import *



def rayTracer(geom, texture, bg = clear, lightDir = norm(P3(1, 2, 2)), ambient  = .5, camera = P3(0, -4, 0), focal = 3):
    center = P3(0,0,0)
    g = center - camera
    g1 = norm(P3(g.x, g.y, 0))
    gn = norm(g)
    xu = P3(g1.y, -g1.x, 0)
    yu = cross(xu, gn)
    vp = gn * focal + camera
    #xu = P3(1, 0, 0)
    #yu = P3(0, 0, 1)
    #vp = P3(0, camera.y + focal, 0)
    def g(p):
        x = p.x
        y = p.y
        point = xu * x + yu * y + vp
        #point = P3(x, camera.y + focal, y)
        ray = (camera, norm(point - camera))
        pn = geom(ray)
        if pn == None:
            return bg
        geomP = pn[0]
        color = texture(geomP)
        geomVec = pn[1]
        i = max(dot(geomVec, lightDir), 0)
        lighting =  ambient + (1 - ambient) * i
        return lighting * color
    return g

def sphereGeom(ray):
    center = P3(0,0,0)
    radius = 1
    origin = ray[0]
    direction = ray[1]
    eo = (center - origin) 
    v = dot(eo,direction)
    vv = dot(eo,eo)
    discrim = v * v - (vv - radius * radius)
    if discrim < 0:
       return None
    t =  v - math.sqrt(discrim)
    if t < 0:
       return None
    sphereP = origin + t * direction
    sphereVec = (sphereP - center)/radius
    return (sphereP, sphereVec)



def cubeGeom(ray):
    origin = ray[0]
    direction = ray[1]
    t = 10000000
    n = P3(1,0,0)
    point = P3(0,0,0)
    #intersect with x
    if direction.x != 0:
        t1 = (1 - origin.x)/direction.x
        if t1 > 0 and t1 < t:
            p = origin + t1 * direction
            if abs(p.y) <= 1 and abs(p.z) <= 1:
                t = t1
                n = P3(1, 0, 0)
                point = p
        t1 = (-1 - origin.x)/direction.x
        if t1 > 0 and t1 < t:
            p = origin + t1 * direction
            if abs(p.y) <= 1 and abs(p.z) <= 1:
                t = t1
                n = P3(-1, 0, 0)
                point = p
    #intersect with y
        if direction.y != 0:
            t2 = (1 - origin.y)/direction.y
            if t2 > 0 and t2 < t:
               p = origin + t2 * direction
               if abs(p.x) <= 1 and abs(p.z) <= 1:
                  t = t2
                  n = P3(0, 1, 0)
                  point = p
            t2 = (-1 - origin.y)/direction.y
            if t2 > 0 and t2 < t:
                p = origin + t2 * direction
                if abs(p.x) <= 1 and abs(p.z) <= 1:
                    t = t2
                    n = P3(0, -1, 0)
                    point = p
    #intersect with z
            if direction.z != 0:
                t3 = (1 - origin.z)/direction.z
                if t3 > 0 and t3 < t:
                   p = origin + t3 * direction
                   if abs(p.x) <= 1 and abs(p.y) <= 1:
                      t = t3
                      n = P3(0, 0, 1)
                      point = p
            t3 = (-1 - origin.z)/direction.z
            if t3 > 0 and t3 < t:
                p = origin + t3 * direction
                if abs(p.x) <= 1 and abs(p.y) <= 1:
                    t = t3
                    n = P3(0, 0, -1)
                    point = p
    if t == 10000000:
        return None
    return (point, n)

def cylinderGeom(ray):
    origin = ray[0]
    direction = ray[1]
    center = P3(0,0,0)
    radius = 1
    height = 1
    centerxy = P2(center.x,center.y)
    originxy = P2(origin.x, origin.y)
    directionxy = norm(P2(direction.x,direction.y))
    eo = (centerxy - originxy) 
    v = dot(eo,directionxy)
    vv = dot(eo,eo)
    t = 10000000

    #intersect with z
    if direction.z != 0:
        t3 = (1 - origin.z)/direction.z
        if t3 > 0 and t3 < t:
            p = origin + t3 * direction
            pp = P2(p.x, p.y)
            if abs(pp) <= 1:
                t = t3
                n = P3(0, 0, 1)
                point = p
        t3 = (-1 - origin.z)/direction.z
        if t3 > 0 and t3 < t:
            p = origin + t3 * direction
            pp = P2(p.x, p.y)
            if abs(pp) <= 1:
                t = t3
                n = P3(0, 0, -1)
                point = p

    #intersect with xy
    discrim = v * v - (vv - radius * radius)
    if discrim >= 0:
        t1 =  v - math.sqrt(discrim)
        if t1 >= 0 and direction.x != 0:
            pointxy = originxy + t1 * directionxy
            t2 = (pointxy.x - origin.x)/direction.x
            if t2 < t:
                p1 = origin + t2 * direction
                print abs(P2(p1.x, p1.y))
                if abs(p1.z) <= 1:
                    t = t2
                    point = p1
                    nxy = (pointxy - centerxy)/radius
                    n = P3(nxy.x, nxy.y, 0)
    if t == 10000000:
       return None
    return (point, n)



